package com.ucode.springboot.starter.fileStorage.provider.aliyun;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.model.Callback;
import com.aliyun.oss.model.Callback.CalbackBodyType;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.CreateBucketRequest;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.ucode.springboot.starter.fileStorage.FsProviderType;
import com.ucode.springboot.starter.fileStorage.UploadObject;
import com.ucode.springboot.starter.fileStorage.UploadResult;
import com.ucode.springboot.starter.fileStorage.provider.AbstractProvider;
import com.ucode.springboot.starter.fileStorage.utils.FilePathHelper;
import com.ucode.tool.base.ResultCodeEnum;
import com.ucode.tool.exception.UcodeServiceException;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;

public class AliyunossProvider extends AbstractProvider {
    
    private OSSClient ossClient;
    private String bucketName;
    private String urlprefix;
    private boolean isPrivate;
    private String accessKey;
    
    public AliyunossProvider(String clientId,String urlprefix,String endpoint, String bucketName, String accessKey, String secretKey,boolean isPrivate) {
        Assert.notBlank(endpoint, "[clientId] not defined");
        Assert.notBlank(endpoint, "[endpoint] not defined");
        Assert.notBlank(bucketName, "[bucketName] not defined");
        Assert.notBlank(accessKey, "[accessKey] not defined");
        Assert.notBlank(secretKey, "[secretKey] not defined");
        Assert.notBlank(urlprefix, "[urlprefix] not defined");
        this.clientId = clientId;
        this.accessKey = accessKey;
        DefaultCredentialProvider defaultCredentialProvider = new DefaultCredentialProvider(accessKey, secretKey);
        //如果你想配置OSSClient的一些细节的参数，可以在构造OSSClient的时候传入ClientConfiguration对象。
        //ClientConfiguration是OSS服务的配置类，可以为客户端配置代理，最大连接数等参数。
        //具体配置看http://aliyun_portal_storage.oss.aliyuncs.com/oss_api/oss_javahtml/OSSClient.html
        //ClientConfiguration conf = new ClientConfiguration();
        ClientConfiguration config = null;
//        // 设置HTTP最大连接数为10
//        conf.setMaxConnections(10);
//        // 设置TCP连接超时为5000毫秒
//        conf.setConnectionTimeout(5000);
//        // 设置最大的重试次数为3
//        conf.setMaxErrorRetry(3);
//        // 设置Socket传输数据超时的时间为2000毫秒
//        conf.setSocketTimeout(2000);
        
        ossClient = new OSSClient(endpoint, defaultCredentialProvider,config);
        this.bucketName = bucketName;
        this.urlprefix = urlprefix.endsWith("/") ? urlprefix : (urlprefix + "/");
        this.isPrivate = isPrivate;
        if (!ossClient.doesBucketExist(bucketName)) {
            ossClient.createBucket(bucketName);
            CreateBucketRequest createBucketRequest= new CreateBucketRequest(bucketName);
            createBucketRequest.setCannedACL(isPrivate ? CannedAccessControlList.Private : CannedAccessControlList.PublicRead);
            ossClient.createBucket(createBucketRequest);
        }
    }
    @Override
    public String providerName() {
        return FsProviderType.aliyun.name();
    }

    @Override
    public UploadResult upload(UploadObject object) {
        String fileName = object.getFileName();
        if(StrUtil.isNotBlank(object.getCatalog())){
            fileName = object.getCatalog().concat(FilePathHelper.DIR_SPLITER).concat(fileName);
        }
        try {
            PutObjectRequest request = null;
            if(object.getFile() != null){
                request = new PutObjectRequest(bucketName, fileName, object.getFile());
            }else if(object.getFileBytes() != null){
                request = new PutObjectRequest(bucketName, fileName, new ByteArrayInputStream(object.getFileBytes()));
            }else if(object.getFileInputStream() != null){
                request = new PutObjectRequest(bucketName, fileName, object.getFileInputStream());
            }else{
                throw new IllegalArgumentException("upload file is NULL");
            }
            
            //https://macrozheng.github.io/mall-learning/#/architect/mall_arch_10
//            Callback callback = new Callback();
//            callback.setCallbackUrl("http://123.57.129.177:8080/api-crm/oss-file/aliyun/callback");
////            callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"filename\\\":${object},"
////                    + "\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},"
////                    + "\\\"height\\\":${imageInfo.height},\\\"width\\\":${imageInfo.width}}");
//            
//            callback.setCallbackBody(DEFAULT_CALLBACK_BODY);
//            callback.setCalbackBodyType(CalbackBodyType.URL);
////            callback.addCallbackVar("x:var1", "value1");
////            callback.addCallbackVar("x:var2", "value2");
//            request.setCallback(callback);
            
            PutObjectResult result = ossClient.putObject(request);
            if(log.isDebugEnabled())
                log.debug("阿里云OSS上传结果:"+JSONUtil.toJsonStr(result));
            if(result.getResponse() != null && !result.getResponse().isSuccessful()){
                throw new RuntimeException(result.getResponse().getErrorResponseAsString());
            }
            return new UploadResult(this.clientId,this.bucketName,this.urlprefix,this.isPrivate,fileName,object.getMimeType());
        } catch (Exception e) {
            log.error(e);
            throw new UcodeServiceException(ResultCodeEnum.FAILED.code, "{}[{}]",providerName(),e.getMessage());
        }
    }

    @Override
    public String getDownloadUrl(String fileKey) {
        if(isPrivate){
//            URL url = ossClient.generatePresignedUrl(bucketName, fileKey, DateUtils.addHours(new Date(), 1));
//            return url.toString().replaceFirst(URL_PREFIX_PATTERN, urlprefix);
        }
        return urlprefix + fileKey;
    }

    @Override
    public boolean delete(String fileKey) {
        ossClient.deleteObject(bucketName, fileKey);
        return true;
    }

    @Override
    public void close() throws IOException {
        ossClient.shutdown();
    }

}
